/**
 *  Copyright 2010 Kyle O'Connor, Justin Arling, Mike Mercieca
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package edu.drexel.sd0910.ece01.aqmon.gui.wizard.impl;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.SwingWorker;

import org.apache.log4j.Logger;

import com.rapplogic.xbee.api.XBeeException;

import edu.drexel.sd0910.ece01.aqmon.data.ActiveNode;
import edu.drexel.sd0910.ece01.aqmon.gui.MainModel;
import edu.drexel.sd0910.ece01.aqmon.gui.wizard.WizardPanelDescriptor;
import edu.drexel.sd0910.ece01.aqmon.util.TimeUtils;

/**
 * Wizard Descriptor - Node Discovery (Range Test) panel. This is the third
 * panel shown during the setup wizard. See
 * {@link edu.drexel.sd0910.ece01.aqmon.gui.wizard.impl.NodeDiscoveryPanel
 * NodeDiscoveryPanel}.
 * 
 * @author Kyle O'Connor
 * 
 */
public class NodeDiscoveryPanelDescriptor extends WizardPanelDescriptor implements ActionListener {

	private final static Logger log = Logger.getLogger(NodeDiscoveryPanelDescriptor.class);

	public static final String IDENTIFIER = "NODE_DISCOVERY_PANEL";

	private NodeDiscoveryPanel panel;

	public NodeDiscoveryPanelDescriptor(MainModel model) {
		panel = new NodeDiscoveryPanel(model);
		this.setPanelIdentifier(IDENTIFIER);
		this.setTargetPanel(panel);
		panel.addNodeDiscoveryButtonListener(this);
	}

	@Override
	public void aboutToDisplayPanel() {
		// start swingworker thread to connect xbee
		new SwingWorker<Void, Void>() {

			@Override
			protected Void doInBackground() throws Exception {
				panel.setButtonEnabled(false);
				getWizard().setNextFinishButtonEnabled(false);
				getWizard().setBackButtonEnabled(false);
				// try to connect
				try {
					panel.model.getXbeeManager().connect(panel.model.getPortName());
					//enable everything to start
					getWizard().setNextFinishButtonEnabled(true);
					getWizard().setBackButtonEnabled(true);
					panel.setButtonEnabled(true);
				} catch (Exception e) {
					log.error(e.toString());
					JOptionPane.showMessageDialog(panel,
							"Error connecting to XBee device. Please go back and detect the proper port.", "Error",
							JOptionPane.ERROR_MESSAGE);
					getWizard().setBackButtonEnabled(true);
					getWizard().setNextFinishButtonEnabled(false);
					panel.setButtonEnabled(false);
					// panel.model.setStatusText("Error connecting to XBee device.");
				}
				return null;

			}
		}.execute();
	}

	@Override
	public void aboutToHidePanel() {
	
	}

	@Override
	public void displayingPanel() {

	}

	@Override
	public Object getBackPanelDescriptor() {
		return PortChooserPanelDescriptor.IDENTIFIER;
	}

	@Override
	public Object getNextPanelDescriptor() {
		return MapPanelDescriptor.IDENTIFIER;
	}
	
	private void startNodeDiscovery(final String revert) {
		new SwingWorker<Void, Void>() {

			@Override
			protected Void doInBackground() throws Exception {
				long timeout = panel.model.getXbeeManager().getNodeDiscoveryTimeout();
				panel.model.setStatusText(revert);
				try {
					panel.model.getXbeeManager().discoverNodes();
				} catch (XBeeException e) {
					log.error(e);
				}
				
				//kick off countdown timer and node status updating
				new NodeStatusWorker(timeout).execute();
				
				return null;
			}
		}.execute();
	}
	
	private class NodeStatusWorker extends SwingWorker<Void, Void> {

		private long timer;

		public NodeStatusWorker(long time) {
			super();
			this.timer = time;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see javax.swing.SwingWorker#doInBackground()
		 */
		@Override
		protected Void doInBackground() throws Exception {
			String status = panel.model.getStatusText(); // to restore later
			int time = (int) (timer / TimeUtils.ONE_SEC_IN_MS);
			panel.model.setStatusText("Discovering nodes (Timeout " + timer + ")...");
			while (time > 0) {
				panel.model.setStatusText("Discovering nodes (Timeout " + time + ")...");
				List<ActiveNode> list = panel.model.getXbeeManager().getActiveNodesList();
				synchronized (list) {
					Iterator<ActiveNode> i = list.iterator();
					while (i.hasNext()) {
						panel.setNodeFound(i.next().getNodeID());
					}
				}

				Thread.sleep(TimeUtils.ONE_SEC_IN_MS);
				time--;
			}
			panel.setButtonEnabled(true);
			getWizard().setNextFinishButtonEnabled(true);
			getWizard().setBackButtonEnabled(true);

			panel.model.setStatusText(status);
			return null;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e) {
		//disable buttons
		panel.setButtonEnabled(false);
		getWizard().setNextFinishButtonEnabled(false);
		getWizard().setBackButtonEnabled(false);
		panel.resetNodeFound(); //reset label statuses
		String s = panel.model.getStatusText(); //save for later
		panel.model.setStatusText("Calculating node discovery timeout period...");
		startNodeDiscovery(s);
	}

}
